#ifndef	__CXX_VIEWS_GRPH_OAL_H__
#define	__CXX_VIEWS_GRPH_OAL_H__

#include "grphbsc.h"

#ifdef TEST_DBG_WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <semaphore.h>
#endif

namespace grphoal
{

class syncobject;
using namespace visgrph;

const uint PAGE_SIZE = 4096;

#ifdef TEST_DBG_WIN32
extern "C" WINBASEAPI
bool WINAPI
TryEnterCriticalSection(
    LPCRITICAL_SECTION lpCriticalSection
    );
#endif

class GRPH_EXPORT_API syncobject
{
protected:

#ifdef TEST_DBG_WIN32
	CRITICAL_SECTION cs;
#else
	unsigned int LockCount;			// remember the count for a same thread
	unsigned int ThreadID;
	sem_t	sem;
#endif

private:
	syncobject(const syncobject&);
	syncobject& operator =(const syncobject&);

public:
	syncobject();
	virtual ~syncobject();
	void sync_start();
	bool sync_start(bool blTrySync);
	void sync_end();
};

class autosync
{
public:
	autosync(syncobject &syncobj);
	~autosync();
private:
	syncobject *m_syncobj;

private:
	autosync(const autosync&);
	autosync& operator =(const autosync&);
};

class procsyncobject
{
protected:
#ifndef __GCC
	HANDLE	handle;
#else
	void* handle;
#endif

private:
	procsyncobject(const procsyncobject& src);
	procsyncobject& operator =(const procsyncobject& src);

public:
	procsyncobject();
	explicit procsyncobject(LPCTSTR name);
	virtual ~procsyncobject();

	bool create(const char* name);
	bool Initialized(void) { return (NULL == handle) ? false : true; }
	void destroy(void);

	bool sync_start(void) const;
	void sync_end() const;
};

class autoprocsync
{
public:

	autoprocsync(procsyncobject &SyncObj) ;

	~autoprocsync() ;
private:
	procsyncobject *m_pSyncObj;

private:
	autoprocsync(const autoprocsync&);
	autoprocsync& operator =(const autoprocsync&);
};

class shared_memory
{
private:
	shared_memory& operator=(shared_memory&);

public:

	shared_memory();
	shared_memory(const char *name, size_t num_pages);
	shared_memory(shared_memory&);
	virtual ~shared_memory();

	void  attach(const char *name, size_t num_pages);
	void  detach(void);
	bool  try_attach(const char *name, size_t num_pages);
	void  assign_to(shared_memory& sharedMem);

	void* address(void) const ;
	uint length(void) const ;
	bool  is_creator(void) ;

private:

#ifdef TEST_DBG_WIN32
	HANDLE	m_Handle;
#else
	int		m_Handle;
#endif
	void*	m_pAddr;
	uint	m_Length;
	bool	m_IsCreator;
};

#define For_Each_List_Item(pitem, l)	\
	for (pitem = (l).GetNext(); pitem != &(l); pitem = pitem->GetNext())

#define LIST_ENTRY(type,member,ptr)	\
	((type *)((unsigned long)(ptr)-(unsigned long)(&((type *)1)->member) + 1))

#define LISTNODE_UP_CAST(type, ptr)	\
	((type *)(((uint)(ptr)) - ((uint)(&(((type *)1)->GetOwnerList()))) + 1))

#define VERIFY_PTR(in)	\
	do {	\
	ASSERT((in) && (in)->GetNext() && (in)->GetPrev());	\
	ASSERT(this && ((this->GetNext() && this->GetPrev())	\
	|| (!this->GetNext() && !this->GetPrev())));	\
	} while(0)

#define VERIFY_THIS()	\
	do {	\
	ASSERT(this && ((this->GetNext() && this->GetPrev())	\
	|| (!this->GetNext() && !this->GetPrev())));	\
	} while(0)

class listnode
{
public:
	void add_to(listnode& head) {
		prev = (head).prev;
		next = (head).prev->next;
		(head).prev->next = this;
		(head).prev = this;
	}

	void add_to_prev(listnode &curr) {
		next = &curr;
		prev = curr.prev;
		curr.prev = this;
		prev->next = this;
	}

	void insert_first(listnode& head)  {
		next = head.next;
		prev = &head;
		head.next->prev = this;
		head.next = this;
	}

	void del(void) {
		prev->next = next;
		next->prev = prev;
		prev = next = this;
	}

	listnode *get_next(void) const { return next; }
	listnode *get_prev(void) const { return prev; }

	bool is_cleared(void) {
		return (prev == NULL && next == NULL)
			? true : false;
	}

	void clear(void)  {
		prev = next = NULL;
	}

	bool is_empty(void)  {
		return (next == this) ? true : false;
	}

public:

	// Initialize this node
	listnode() {
	 	next = this;
		prev = this;
	}

private:

	listnode *next;
	listnode *prev;

private:
	listnode(const listnode&);
	listnode& operator =(const listnode&);
};

namespace md5gen_imp {
	struct MD5_CTX;
};

struct uint128_t
{
    unsigned int data1;
    unsigned short data2;
    unsigned short data3;
    unsigned char data4[8];
};

class md5gen
{
public:
	md5gen();
	md5gen(void *pData, size_t sz);
	~md5gen();

	void encode(void* pData, size_t sz);
	uint128_t result(void) { return m_Result; }

private:
	md5gen_imp::MD5_CTX *m_pMd5;
	uint128_t	m_Result;
};

inline static void atomic_set(unsigned int* addr, unsigned int val)
{
	__asm {
		mov	eax, addr
		mov ebx, val
		mov [eax], ebx
	}
}

};	// namespace grphoal

#endif	// __CXX_VIEWS_GRPH_OAL_H__
/* EOF */
